#include <stm32f1xx_hal.h>
#include <board.h>

#ifndef OLED_WIDTH
#define OLED_WIDTH   128
#endif
#ifndef OLED_HEIGHT
#define OLED_HEIGHT   64  /* 若你的屏为 128x32，请在编译宏中定义 OLED_HEIGHT=32 */
#endif
#define OLED_PAGES   (OLED_HEIGHT / 8)
#include "OLED.h"
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdarg.h>

/*
HAL 适配说明：
 - 使用 PB8 作为 SCL，PB9 作为 SDA，开漏上拉（外部上拉电阻或内部上拉）。
 - 通过GPIO位操作实现软件I2C，与原始接口保持一致：OLED_W_SCL / OLED_W_SDA。
*/

static void OLED_W_SCL(uint8_t BitValue);
static void OLED_W_SDA(uint8_t BitValue);
static void OLED_GPIO_Init(void);
static void OLED_I2C_Start(void);
static void OLED_I2C_Stop(void);
static void OLED_I2C_SendByte(uint8_t Byte);
static void OLED_WriteCommand(uint8_t Command);
static void OLED_WriteData(uint8_t *Data, uint8_t Count);
static void OLED_SetCursor(uint8_t Page, uint8_t X);
static uint32_t OLED_Pow(uint32_t X, uint32_t Y);
void OLED_ShowImage(int16_t X, int16_t Y, uint8_t Width, uint8_t Height, const uint8_t *Image);

uint8_t OLED_DisplayBuf[8][128];

static void OLED_W_SCL(uint8_t BitValue)
{
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, BitValue ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

static void OLED_W_SDA(uint8_t BitValue)
{
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, BitValue ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

static void OLED_GPIO_Init(void)
{
	uint32_t i, j;
	for (i = 0; i < 1000; i ++)
	{
		for (j = 0; j < 1000; j ++);
	}

	__HAL_RCC_GPIOB_CLK_ENABLE();
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;  /* 开漏输出 */
	GPIO_InitStruct.Pull = GPIO_PULLUP;          /* 使能上拉 */
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	OLED_W_SCL(1);
	OLED_W_SDA(1);
}

static void OLED_I2C_Start(void)
{
	OLED_W_SDA(1);
	OLED_W_SCL(1);
	OLED_W_SDA(0);
	OLED_W_SCL(0);
}

static void OLED_I2C_Stop(void)
{
	OLED_W_SDA(0);
	OLED_W_SCL(1);
	OLED_W_SDA(1);
}

static void OLED_I2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		OLED_W_SDA(!!(Byte & (0x80 >> i)));
		OLED_W_SCL(1);
		OLED_W_SCL(0);
	}
	OLED_W_SCL(1);
	OLED_W_SCL(0);
}

static void OLED_WriteCommand(uint8_t Command)
{
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78);
	OLED_I2C_SendByte(0x00);
	OLED_I2C_SendByte(Command);
	OLED_I2C_Stop();
}

static void OLED_WriteData(uint8_t *Data, uint8_t Count)
{
	uint8_t i;
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78);
	OLED_I2C_SendByte(0x40);
	for (i = 0; i < Count; i ++)
	{
		OLED_I2C_SendByte(Data[i]);
	}
	OLED_I2C_Stop();
}

void OLED_Init(void)
{
	OLED_GPIO_Init();
    OLED_WriteCommand(0xAE);                 /* display off */
    OLED_WriteCommand(0x20);                 /* Set Memory Addressing Mode */
    OLED_WriteCommand(0x02);                 /* Page Addressing Mode */
	OLED_WriteCommand(0xD5);
	OLED_WriteCommand(0x80);
	OLED_WriteCommand(0xA8);
    #if (OLED_HEIGHT == 64)
    OLED_WriteCommand(0x3F);                 /* multiplex ratio for 64 */
    #else
    OLED_WriteCommand(0x1F);                 /* multiplex ratio for 32 */
    #endif
	OLED_WriteCommand(0xD3);
	OLED_WriteCommand(0x00);
	OLED_WriteCommand(0x40);
	OLED_WriteCommand(0xA1);
	OLED_WriteCommand(0xC8);
	OLED_WriteCommand(0xDA);
    #if (OLED_HEIGHT == 64)
    OLED_WriteCommand(0x12);                 /* COM pins config for 64 */
    #else
    OLED_WriteCommand(0x02);                 /* COM pins config for 32 */
    #endif
	OLED_WriteCommand(0x81);
	OLED_WriteCommand(0xCF);
	OLED_WriteCommand(0xD9);
	OLED_WriteCommand(0xF1);
	OLED_WriteCommand(0xDB);
	OLED_WriteCommand(0x30);
	OLED_WriteCommand(0xA4);
	OLED_WriteCommand(0xA6);
	OLED_WriteCommand(0x8D);
	OLED_WriteCommand(0x14);
	OLED_WriteCommand(0xAF);
	OLED_Clear();
	OLED_Update();
}

static void OLED_SetCursor(uint8_t Page, uint8_t X)
{
	OLED_WriteCommand(0xB0 | Page);
	OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));
	OLED_WriteCommand(0x00 | (X & 0x0F));
}

void OLED_Update(void)
{
    uint8_t j;
    for (j = 0; j < OLED_PAGES; j ++)
	{
		OLED_SetCursor(j, 0);
        OLED_WriteData(OLED_DisplayBuf[j], OLED_WIDTH);
	}
}

void OLED_UpdateArea(int16_t X, int16_t Y, uint8_t Width, uint8_t Height)
{
	int16_t j;
	int16_t Page, Page1;
	Page = Y / 8;
	Page1 = (Y + Height - 1) / 8 + 1;
	if (Y < 0)
	{
		Page -= 1;
		Page1 -= 1;
	}
	for (j = Page; j < Page1; j ++)
	{
        if (X >= 0 && X <= (OLED_WIDTH - 1) && j >= 0 && j <= (OLED_PAGES - 1))
		{
			OLED_SetCursor(j, (uint8_t)X);
			OLED_WriteData(&OLED_DisplayBuf[j][X], Width);
		}
	}
}

void OLED_Clear(void)
{
	uint8_t i, j;
    for (j = 0; j < OLED_PAGES; j ++)
	{
        for (i = 0; i < OLED_WIDTH; i ++)
		{
			OLED_DisplayBuf[j][i] = 0x00;
		}
	}
}

void OLED_ClearArea(int16_t X, int16_t Y, uint8_t Width, uint8_t Height)
{
	int16_t i, j;
	for (j = Y; j < Y + Height; j ++)
	{
		for (i = X; i < X + Width; i ++)
		{
            if (i >= 0 && i <= (OLED_WIDTH - 1) && j >=0 && j <= (OLED_HEIGHT - 1))
			{
				OLED_DisplayBuf[j / 8][i] &= ~(0x01 << (j % 8));
			}
		}
	}
}

void OLED_Reverse(void)
{
	uint8_t i, j;
    for (j = 0; j < OLED_PAGES; j ++)
	{
        for (i = 0; i < OLED_WIDTH; i ++)
		{
			OLED_DisplayBuf[j][i] ^= 0xFF;
		}
	}
}

void OLED_ReverseArea(int16_t X, int16_t Y, uint8_t Width, uint8_t Height)
{
	int16_t i, j;
	for (j = Y; j < Y + Height; j ++)
	{
		for (i = X; i < X + Width; i ++)
		{
            if (i >= 0 && i <= (OLED_WIDTH - 1) && j >=0 && j <= (OLED_HEIGHT - 1))
			{
				OLED_DisplayBuf[j / 8][i] ^= 0x01 << (j % 8);
			}
		}
	}
}

static uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y --)
	{
		Result *= X;
	}
	return Result;
}

void OLED_ShowChar(int16_t X, int16_t Y, char Char, uint8_t FontSize)
{
	if (FontSize == OLED_8X16)
	{
		OLED_ShowImage(X, Y, 8, 16, OLED_F8x16[(uint8_t)Char - ' ']);
	}
	else if(FontSize == OLED_6X8)
	{
		OLED_ShowImage(X, Y, 6, 8, OLED_F6x8[(uint8_t)Char - ' ']);
	}
}

void OLED_ShowString(int16_t X, int16_t Y, char *String, uint8_t FontSize)
{
	uint16_t i = 0;
	char SingleChar[5];
	uint8_t CharLength = 0;
	uint16_t XOffset = 0;
	uint16_t pIndex;
	while (String[i] != '\0')
	{
#ifdef OLED_CHARSET_UTF8
		if ((String[i] & 0x80) == 0x00)
		{
			CharLength = 1;
			SingleChar[0] = String[i ++];
			SingleChar[1] = '\0';
		}
		else if ((String[i] & 0xE0) == 0xC0)
		{
			CharLength = 2;
			SingleChar[0] = String[i ++];
			if (String[i] == '\0') {break;}
			SingleChar[1] = String[i ++];
			SingleChar[2] = '\0';
		}
		else if ((String[i] & 0xF0) == 0xE0)
		{
			CharLength = 3;
			SingleChar[0] = String[i ++];
			if (String[i] == '\0') {break;}
			SingleChar[1] = String[i ++];
			if (String[i] == '\0') {break;}
			SingleChar[2] = String[i ++];
			SingleChar[3] = '\0';
		}
		else if ((String[i] & 0xF8) == 0xF0)
		{
			CharLength = 4;
			SingleChar[0] = String[i ++];
			if (String[i] == '\0') {break;}
			SingleChar[1] = String[i ++];
			if (String[i] == '\0') {break;}
			SingleChar[2] = String[i ++];
			if (String[i] == '\0') {break;}
			SingleChar[3] = String[i ++];
			SingleChar[4] = '\0';
		}
		else
		{
			i ++;
			continue;
		}
#endif

		if (CharLength == 1)
		{
			OLED_ShowChar(X + XOffset, Y, SingleChar[0], FontSize);
			XOffset += FontSize;
		}
		else
		{
			for (pIndex = 0; strcmp(OLED_CF16x16[pIndex].Index, "") != 0; pIndex ++)
			{
				if (strcmp(OLED_CF16x16[pIndex].Index, SingleChar) == 0)
				{
					break;
				}
			}
			if (FontSize == OLED_8X16)
			{
				OLED_ShowImage(X + XOffset, Y, 16, 16, OLED_CF16x16[pIndex].Data);
				XOffset += 16;
			}
			else if (FontSize == OLED_6X8)
			{
				OLED_ShowChar(X + XOffset, Y, '?', OLED_6X8);
				XOffset += OLED_6X8;
			}
		}
	}
}

void OLED_ShowNum(int16_t X, int16_t Y, uint32_t Number, uint8_t Length, uint8_t FontSize)
{
	uint8_t i;
	for (i = 0; i < Length; i++)
	{
		OLED_ShowChar(X + i * FontSize, Y, Number / OLED_Pow(10, Length - i - 1) % 10 + '0', FontSize);
	}
}

void OLED_ShowSignedNum(int16_t X, int16_t Y, int32_t Number, uint8_t Length, uint8_t FontSize)
{
	uint8_t i;
	uint32_t Number1;
	if (Number >= 0)
	{
		OLED_ShowChar(X, Y, '+', FontSize);
		Number1 = (uint32_t)Number;
	}
	else
	{
		OLED_ShowChar(X, Y, '-', FontSize);
		Number1 = (uint32_t)(-Number);
	}
	for (i = 0; i < Length; i++)
	{
		OLED_ShowChar(X + (i + 1) * FontSize, Y, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0', FontSize);
	}
}

void OLED_ShowHexNum(int16_t X, int16_t Y, uint32_t Number, uint8_t Length, uint8_t FontSize)
{
	uint8_t i, SingleNumber;
	for (i = 0; i < Length; i++)
	{
		SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
		if (SingleNumber < 10)
		{
			OLED_ShowChar(X + i * FontSize, Y, SingleNumber + '0', FontSize);
		}
		else
		{
			OLED_ShowChar(X + i * FontSize, Y, SingleNumber - 10 + 'A', FontSize);
		}
	}
}

void OLED_ShowBinNum(int16_t X, int16_t Y, uint32_t Number, uint8_t Length, uint8_t FontSize)
{
	uint8_t i;
	for (i = 0; i < Length; i++)
	{
		OLED_ShowChar(X + i * FontSize, Y, Number / OLED_Pow(2, Length - i - 1) % 2 + '0', FontSize);
	}
}

void OLED_ShowFloatNum(int16_t X, int16_t Y, double Number, uint8_t IntLength, uint8_t FraLength, uint8_t FontSize)
{
	uint32_t PowNum, IntNum, FraNum;
	if (Number >= 0)
	{
		OLED_ShowChar(X, Y, '+', FontSize);
	}
	else
	{
		OLED_ShowChar(X, Y, '-', FontSize);
		Number = -Number;
	}
	IntNum = (uint32_t)Number;
	Number -= IntNum;
	PowNum = (uint32_t)OLED_Pow(10, FraLength);
	FraNum = (uint32_t)round(Number * PowNum);
	IntNum += FraNum / PowNum;
	OLED_ShowNum(X + FontSize, Y, IntNum, IntLength, FontSize);
	OLED_ShowChar(X + (IntLength + 1) * FontSize, Y, '.', FontSize);
	OLED_ShowNum(X + (IntLength + 2) * FontSize, Y, FraNum, FraLength, FontSize);
}

void OLED_ShowImage(int16_t X, int16_t Y, uint8_t Width, uint8_t Height, const uint8_t *Image)
{
	uint8_t i = 0, j = 0;
	int16_t Page, Shift;
	OLED_ClearArea(X, Y, Width, Height);
	for (j = 0; j < (Height - 1) / 8 + 1; j ++)
	{
		for (i = 0; i < Width; i ++)
		{
            if (X + i >= 0 && X + i <= (OLED_WIDTH - 1))
			{
				Page = Y / 8;
				Shift = Y % 8;
				if (Y < 0)
				{
					Page -= 1;
					Shift += 8;
				}
                if (Page + j >= 0 && Page + j <= (OLED_PAGES - 1))
				{
					OLED_DisplayBuf[Page + j][X + i] |= Image[j * Width + i] << (Shift);
				}
                if (Page + j + 1 >= 0 && Page + j + 1 <= (OLED_PAGES - 1))
				{
					OLED_DisplayBuf[Page + j + 1][X + i] |= Image[j * Width + i] >> (8 - Shift);
				}
			}
		}
	}
}

void OLED_DrawPoint(int16_t X, int16_t Y)
{
    if (X >= 0 && X <= (OLED_WIDTH - 1) && Y >=0 && Y <= (OLED_HEIGHT - 1))
	{
		OLED_DisplayBuf[Y / 8][X] |= 0x01 << (Y % 8);
	}
}

uint8_t OLED_GetPoint(int16_t X, int16_t Y)
{
    if (X >= 0 && X <= (OLED_WIDTH - 1) && Y >=0 && Y <= (OLED_HEIGHT - 1))
	{
		if (OLED_DisplayBuf[Y / 8][X] & 0x01 << (Y % 8))
		{
			return 1;
		}
	}
	return 0;
}

void OLED_DrawLine(int16_t X0, int16_t Y0, int16_t X1, int16_t Y1)
{
	int16_t x, y, dx, dy, d, incrE, incrNE, temp;
	int16_t x0 = X0, y0 = Y0, x1 = X1, y1 = Y1;
	uint8_t yflag = 0, xyflag = 0;
	if (y0 == y1)
	{
		if (x0 > x1) {temp = x0; x0 = x1; x1 = temp;}
		for (x = x0; x <= x1; x ++)
		{
			OLED_DrawPoint(x, y0);
		}
	}
	else if (x0 == x1)
	{
		if (y0 > y1) {temp = y0; y0 = y1; y1 = temp;}
		for (y = y0; y <= y1; y ++)
		{
			OLED_DrawPoint(x0, y);
		}
	}
	else
	{
		if (x0 > x1)
		{
			temp = x0; x0 = x1; x1 = temp;
			temp = y0; y0 = y1; y1 = temp;
		}
		if (y0 > y1)
		{
			y0 = -y0;
			y1 = -y1;
			yflag = 1;
		}
		if (y1 - y0 > x1 - x0)
		{
			temp = x0; x0 = y0; y0 = temp;
			temp = x1; x1 = y1; y1 = temp;
			xyflag = 1;
		}
		dx = x1 - x0;
		dy = y1 - y0;
		incrE = 2 * dy;
		incrNE = 2 * (dy - dx);
		d = 2 * dy - dx;
		x = x0;
		y = y0;
		if (yflag && xyflag){OLED_DrawPoint(y, -x);} else if (yflag){OLED_DrawPoint(x, -y);} else if (xyflag){OLED_DrawPoint(y, x);} else {OLED_DrawPoint(x, y);} 
		while (x < x1)
		{
			x ++;
			if (d < 0)
			{
				d += incrE;
			}
			else
			{
				y ++;
				d += incrNE;
			}
			if (yflag && xyflag){OLED_DrawPoint(y, -x);} else if (yflag){OLED_DrawPoint(x, -y);} else if (xyflag){OLED_DrawPoint(y, x);} else {OLED_DrawPoint(x, y);} 
		}
	}
}

void OLED_DrawRectangle(int16_t X, int16_t Y, uint8_t Width, uint8_t Height, uint8_t IsFilled)
{
	int16_t i, j;
	if (!IsFilled)
	{
		for (i = X; i < X + Width; i ++)
		{
			OLED_DrawPoint(i, Y);
			OLED_DrawPoint(i, Y + Height - 1);
		}
		for (i = Y; i < Y + Height; i ++)
		{
			OLED_DrawPoint(X, i);
			OLED_DrawPoint(X + Width - 1, i);
		}
	}
	else
	{
		for (i = X; i < X + Width; i ++)
		{
			for (j = Y; j < Y + Height; j ++)
			{
				OLED_DrawPoint(i, j);
			}
		}
	}
}

void OLED_DrawTriangle(int16_t X0, int16_t Y0, int16_t X1, int16_t Y1, int16_t X2, int16_t Y2, uint8_t IsFilled)
{
	int16_t minx = X0, miny = Y0, maxx = X0, maxy = Y0;
	int16_t i, j;
	int16_t vx[] = {X0, X1, X2};
	int16_t vy[] = {Y0, Y1, Y2};
	if (!IsFilled)
	{
		OLED_DrawLine(X0, Y0, X1, Y1);
		OLED_DrawLine(X0, Y0, X2, Y2);
		OLED_DrawLine(X1, Y1, X2, Y2);
	}
	else
	{
		if (X1 < minx) {minx = X1;}
		if (X2 < minx) {minx = X2;}
		if (Y1 < miny) {miny = Y1;}
		if (Y2 < miny) {miny = Y2;}
		if (X1 > maxx) {maxx = X1;}
		if (X2 > maxx) {maxx = X2;}
		if (Y1 > maxy) {maxy = Y1;}
		if (Y2 > maxy) {maxy = Y2;}
		for (i = minx; i <= maxx; i ++)
		{
			for (j = miny; j <= maxy; j ++)
			{
				int16_t c = 0;
				int16_t k, l;
				for (k = 0, l = 2; k < 3; l = k++)
				{
					if (((vy[k] > j) != (vy[l] > j)) && (i < (vx[l] - vx[k]) * (j - vy[k]) / (vy[l] - vy[k]) + vx[k]))
					{
						c = !c;
					}
				}
				if (c) {OLED_DrawPoint(i, j);} 
			}
		}
	}
}

void OLED_DrawCircle(int16_t X, int16_t Y, uint8_t Radius, uint8_t IsFilled)
{
	int16_t x, y, d, j;
	d = 1 - Radius;
	x = 0;
	y = Radius;
	OLED_DrawPoint(X + x, Y + y);
	OLED_DrawPoint(X - x, Y - y);
	OLED_DrawPoint(X + y, Y + x);
	OLED_DrawPoint(X - y, Y - x);
	if (IsFilled)
	{
		for (j = -y; j < y; j ++)
		{
			OLED_DrawPoint(X, Y + j);
		}
	}
	while (x < y)
	{
		x ++;
		if (d < 0)
		{
			d += 2 * x + 1;
		}
		else
		{
			y --;
			d += 2 * (x - y) + 1;
		}
		OLED_DrawPoint(X + x, Y + y);
		OLED_DrawPoint(X + y, Y + x);
		OLED_DrawPoint(X - x, Y - y);
		OLED_DrawPoint(X - y, Y - x);
		OLED_DrawPoint(X + x, Y - y);
		OLED_DrawPoint(X + y, Y - x);
		OLED_DrawPoint(X - x, Y + y);
		OLED_DrawPoint(X - y, Y + x);
		if (IsFilled)
		{
			for (j = -y; j < y; j ++)
			{
				OLED_DrawPoint(X + x, Y + j);
				OLED_DrawPoint(X - x, Y + j);
			}
			for (j = -x; j < x; j ++)
			{
				OLED_DrawPoint(X - y, Y + j);
				OLED_DrawPoint(X + y, Y + j);
			}
		}
	}
}

void OLED_DrawEllipse(int16_t X, int16_t Y, uint8_t A, uint8_t B, uint8_t IsFilled)
{
	int16_t x, y, j;
	int16_t a = A, b = B;
	float d1, d2;
	x = 0;
	y = b;
	d1 = b * b + a * a * (-b + 0.5f);
	if (IsFilled)
	{
		for (j = -y; j < y; j ++)
		{
			OLED_DrawPoint(X, Y + j);
			OLED_DrawPoint(X, Y + j);
		}
	}
	OLED_DrawPoint(X + x, Y + y);
	OLED_DrawPoint(X - x, Y - y);
	OLED_DrawPoint(X - x, Y + y);
	OLED_DrawPoint(X + x, Y - y);
	while (b * b * (x + 1) < a * a * (y - 0.5f))
	{
		if (d1 <= 0)
		{
			d1 += b * b * (2 * x + 3);
		}
		else
		{
			d1 += b * b * (2 * x + 3) + a * a * (-2 * y + 2);
			y --;
		}
		x ++;
		if (IsFilled)
		{
			for (j = -y; j < y; j ++)
			{
				OLED_DrawPoint(X + x, Y + j);
				OLED_DrawPoint(X - x, Y + j);
			}
		}
		OLED_DrawPoint(X + x, Y + y);
		OLED_DrawPoint(X - x, Y - y);
		OLED_DrawPoint(X - x, Y + y);
		OLED_DrawPoint(X + x, Y - y);
	}
	d2 = b * b * (x + 0.5f) * (x + 0.5f) + a * a * (y - 1) * (y - 1) - a * a * b * b;
	while (y > 0)
	{
		if (d2 <= 0)
		{
			d2 += b * b * (2 * x + 2) + a * a * (-2 * y + 3);
			x ++;
		}
		else
		{
			d2 += a * a * (-2 * y + 3);
		}
		y --;
		if (IsFilled)
		{
			for (j = -y; j < y; j ++)
			{
				OLED_DrawPoint(X + x, Y + j);
				OLED_DrawPoint(X - x, Y + j);
			}
		}
		OLED_DrawPoint(X + x, Y + y);
		OLED_DrawPoint(X - x, Y - y);
		OLED_DrawPoint(X - x, Y + y);
		OLED_DrawPoint(X + x, Y - y);
	}
}

static uint8_t OLED_IsInAngle_Helper(int16_t px, int16_t py, int16_t StartAngle, int16_t EndAngle)
{
    int16_t ang = (int16_t)(atan2((float)py, (float)px) / 3.14f * 180);
    if (StartAngle < EndAngle)
    {
        return (ang >= StartAngle && ang <= EndAngle) ? 1 : 0;
    }
    else
    {
        return (ang >= StartAngle || ang <= EndAngle) ? 1 : 0;
    }
}

void OLED_DrawArc(int16_t X, int16_t Y, uint8_t Radius, int16_t StartAngle, int16_t EndAngle, uint8_t IsFilled)
{
    int16_t x, y, d, j;
	d = 1 - Radius;
	x = 0;
	y = Radius;
    if (OLED_IsInAngle_Helper(x, y, StartAngle, EndAngle)) {OLED_DrawPoint(X + x, Y + y);} 
    if (OLED_IsInAngle_Helper(-x, -y, StartAngle, EndAngle)) {OLED_DrawPoint(X - x, Y - y);} 
    if (OLED_IsInAngle_Helper(y, x, StartAngle, EndAngle)) {OLED_DrawPoint(X + y, Y + x);} 
    if (OLED_IsInAngle_Helper(-y, -x, StartAngle, EndAngle)) {OLED_DrawPoint(X - y, Y - x);} 
	if (IsFilled)
	{
		for (j = -y; j < y; j ++)
		{
            if (OLED_IsInAngle_Helper(0, j, StartAngle, EndAngle)) {OLED_DrawPoint(X, Y + j);} 
		}
	}
	while (x < y)
	{
		x ++;
		if (d < 0) { d += 2 * x + 1; }
		else { y --; d += 2 * (x - y) + 1; }
        if (OLED_IsInAngle_Helper(x, y, StartAngle, EndAngle)) {OLED_DrawPoint(X + x, Y + y);} 
        if (OLED_IsInAngle_Helper(y, x, StartAngle, EndAngle)) {OLED_DrawPoint(X + y, Y + x);} 
        if (OLED_IsInAngle_Helper(-x, -y, StartAngle, EndAngle)) {OLED_DrawPoint(X - x, Y - y);} 
        if (OLED_IsInAngle_Helper(-y, -x, StartAngle, EndAngle)) {OLED_DrawPoint(X - y, Y - x);} 
        if (OLED_IsInAngle_Helper(x, -y, StartAngle, EndAngle)) {OLED_DrawPoint(X + x, Y - y);} 
        if (OLED_IsInAngle_Helper(y, -x, StartAngle, EndAngle)) {OLED_DrawPoint(X + y, Y - x);} 
        if (OLED_IsInAngle_Helper(-x, y, StartAngle, EndAngle)) {OLED_DrawPoint(X - x, Y + y);} 
        if (OLED_IsInAngle_Helper(-y, x, StartAngle, EndAngle)) {OLED_DrawPoint(X - y, Y + x);} 
		if (IsFilled)
		{
			for (j = -y; j < y; j ++)
			{
                if (OLED_IsInAngle_Helper(x, j, StartAngle, EndAngle)) {OLED_DrawPoint(X + x, Y + j);} 
                if (OLED_IsInAngle_Helper(-x, j, StartAngle, EndAngle)) {OLED_DrawPoint(X - x, Y + j);} 
			}
			for (j = -x; j < x; j ++)
			{
                if (OLED_IsInAngle_Helper(-y, j, StartAngle, EndAngle)) {OLED_DrawPoint(X - y, Y + j);} 
                if (OLED_IsInAngle_Helper(y, j, StartAngle, EndAngle)) {OLED_DrawPoint(X + y, Y + j);} 
			}
		}
	}
}


